package query

import (
	"strings"
)

//Calculator 计算接口
type Calculator interface {
	Do(context map[string][]string, aggType string, exps ...string) (*float64, error)
}

//CalculateFunc 计算函数类型
type CalculateFunc func(context map[string][]string, aggType string, exps ...string) (*float64, error)

//Do 执行运算
func (c CalculateFunc) Do(context map[string][]string, aggType string, exps ...string) (*float64, error) {
	return c(context, aggType, exps...)
}
func plus(context map[string][]string, aggType string, exps ...string) (*float64, error) {
	vals, err := getExpValues(context, aggType, exps...)
	if err != nil {
		return nil, err
	}
	var retVal float64
	for _, val := range vals {
		if val != nil {
			retVal += *val
		}
	}
	return &retVal, nil
}
func minus(context map[string][]string, aggType string, exps ...string) (*float64, error) {
	vals, err := getExpValues(context, aggType, exps...)
	if err != nil {
		return nil, err
	}
	var retVal float64
	if vals[0] != nil {
		retVal = *vals[0]
	}
	for i := 1; i <= len(vals); i++ {
		if vals[i] != nil {
			retVal -= *vals[i]
		}
	}
	return &retVal, nil
}
func multiply(context map[string][]string, aggType string, exps ...string) (*float64, error) {
	vals, err := getExpValues(context, aggType, exps...)
	if err != nil {
		return nil, err
	}
	var retVal float64
	for _, val := range vals {
		if val != nil {
			retVal *= *val
		}
	}
	return &retVal, nil
}
func division(context map[string][]string, aggType string, exps ...string) (*float64, error) {
	vals, err := getExpValues(context, aggType, exps...)
	if err != nil {
		return nil, err
	}
	var retVal float64
	if vals[0] != nil {
		retVal = *vals[0]
	}
	for i := 1; i <= len(vals); i++ {
		if vals[i] != nil {
			retVal /= *vals[i]
		}
	}
	return &retVal, nil
}
func getExpValues(context map[string][]string, aggType string, exps ...string) (vals []*float64, err error) {
	eLen := len(exps)
	vals = make([]*float64, eLen, eLen)
	var val *float64
	for i, exp := range exps {
		if strings.HasPrefix(exp, "@") {
			ind := string(([]byte(exp))[1:])
			val, err = GetIndexValue(ind, context)
		} else {
			val, err = getValueByExp(exp, aggType, context)
		}
		if err != nil {
			return nil, err
		}
		vals[i] = val
	}
	return
}

var calcMap map[string]Calculator

func init() {
	calcMap = make(map[string]Calculator)
	calcMap["plus"] = CalculateFunc(plus)
	calcMap["minus"] = CalculateFunc(minus)
	calcMap["multiply"] = CalculateFunc(multiply)
	calcMap["division"] = CalculateFunc(division)
}
